
#include "SmartWorldExtensions.h"

#include "EditorActorFolders.h"
#include "FileHelpers.h"
#include "EditorLevelLibrary.h"
#include "Engine/LevelStreamingDynamic.h"


TArray<ULevel*> USmartWorldExtensions::SmGetLevels(UWorld * World, bool bIsReference)
{
	TArray<ULevel*> ResultLevels;
	if (World) {
		if (bIsReference){
			for (ULevel* Level : World->GetLevels()) {
				if (!Level->IsPersistentLevel()) {
					ResultLevels.Add(Level);
				}
			}
		}
		else {
			return World->GetLevels();
		}
	}
	return ResultLevels;
}

const TArray<ULevelStreaming*>& USmartWorldExtensions::SmGetStreamingLevels(UWorld * World)
{
	return World->GetStreamingLevels();
}

ULevel * USmartWorldExtensions::SmGetCurrentLevel(UWorld * World)
{
	return World->GetCurrentLevel();
}

bool USmartWorldExtensions::SmSetCurrentLevel(UWorld * World, ULevel * InLevel)
{
	return World->SetCurrentLevel(InLevel);
}

void USmartWorldExtensions::SmSetAllLevelsLocked(UWorld* World, bool bIsLocked)
{
	UEditorLevelLibrary::SelectNothing();
	const TArray<ULevelStreaming*>& StreamingLevels = World->GetStreamingLevels();
	for (ULevelStreaming* LevelStreaming : StreamingLevels) {
		LevelStreaming->bLocked = bIsLocked;
	}
}

void USmartWorldExtensions::SmSetAllLevelsVisible(UWorld* World, bool bIsVisible)
{
	const TArray<ULevelStreaming*>& StreamingLevels = World->GetStreamingLevels();
	for (ULevelStreaming* LevelStreaming : StreamingLevels) {
		LevelStreaming->SetShouldBeVisible(bIsVisible);
		LevelStreaming->SetShouldBeVisibleInEditor(bIsVisible);
	}
	World->FlushLevelStreaming();
}

ULevel * USmartWorldExtensions::SmGetPersistentLevel(UWorld * World)
{
	return World->PersistentLevel;
}

bool USmartWorldExtensions::SmCurrentIsPersistentLevel(UWorld* World)
{
	return World->GetCurrentLevel()->IsPersistentLevel();
}

TArray<AActor*> USmartWorldExtensions::SmGetActors(UWorld* World, bool bIsSub)
{
	TArray<AActor*> Actors;
	if (bIsSub) {
		for (const ULevel* Level : World->GetLevels()) {
			Actors.Append(Level->Actors);
		}
	}
	else {
		ULevel * Level = World->GetCurrentLevel();
		return Level->Actors;
	}
	return Actors;
}

TArray<AActor*> USmartWorldExtensions::SmFindActorsByLabel(UWorld* World, FString Label, bool bIsSub)
{
	TArray<AActor*> Actors;
	if (bIsSub) {
		for (ULevel* Level : World->GetLevels()) {
			for (AActor * Actor : Level->Actors) {
				if (Label == Actor->GetActorLabel()) {
					Actors.Add(Actor);
				}
			}
		}
	}
	else {
		ULevel * Level = World->GetCurrentLevel();
		for (AActor * Actor : Level->Actors) {
			if (Label == Actor->GetActorLabel()) {
				Actors.Add(Actor);
			}
		}
	}
	return Actors;
}

void USmartWorldExtensions::SmCreateFolder(UWorld* World, FString Name)
{
	const TArray<FString> AllFolders = SmGetAllFolders(World);
	if (!AllFolders.Contains(Name)) {
		FActorFolders::Get().CreateFolder(*World, FName(*Name));
	}
}

void USmartWorldExtensions::SmRenameFolder(UWorld* World, FString OldName, FString NewName)
{
	const TArray<FString> AllFolders = SmGetAllFolders(World);
	if (AllFolders.Contains(OldName)) {
		FActorFolders::Get().RenameFolderInWorld(*World, FName(*OldName), FName(*NewName));
	}
}

void USmartWorldExtensions::SmAddActorsToFolder(UWorld* World, FString Name, TArray<AActor*> Actors)
{
	SmCreateFolder(World, Name);
	for (AActor* Actor : Actors) {
		Actor->SetFolderPath_Recursively(FName(*Name));
	}
}

TArray<FString> USmartWorldExtensions::SmGetAllFolders(UWorld* World) {
	TArray<FString> AllFolders;
	const auto& ExistingFolders = FActorFolders::Get().GetFolderPropertiesForWorld(*World);
	TArray<FName> FolderNames;
	ExistingFolders.GetKeys(FolderNames);
	for (FName Name : FolderNames){
		AllFolders.Add(Name.ToString());
	}
	return AllFolders;
}

void USmartWorldExtensions::SmAddLevel(UWorld* World, FString PackageName)
{
	TArray<ULevel*> ReferenceLevels = SmGetLevels(World, true);
	if (ReferenceLevels.Num()) {
		const FString LevelName = FPaths::GetBaseFilename(PackageName);
		const FString LevelRoot = FPaths::GetPath(PackageName);
		for (const ULevel* RefLevel : ReferenceLevels) {
			FString RefLevelPath = RefLevel->GetOuter()->GetPathName();
			FString RefLevelName = FPaths::GetBaseFilename(RefLevelPath);
			FString RefLevelRoot = FPaths::GetPath(RefLevelPath);
			if (LevelName == RefLevelName) {
				if (LevelRoot == RefLevelRoot) {
					return;
				}
			}
		}
	}
	// UClass* StreamingClass = ULevelStreamingKismet::StaticClass();
	const UClass* StreamingClass = ULevelStreamingDynamic::StaticClass();
	ULevelStreaming* StreamingLevel = Cast<ULevelStreaming>(StaticConstructObject_Internal(StreamingClass, World));
	const FName LevelPackageName = FName::FName(*PackageName);
	StreamingLevel->SetWorldAssetByPackageName(LevelPackageName);
	StreamingLevel->SetShouldBeLoaded(true);
	StreamingLevel->SetShouldBeVisible(true);
	StreamingLevel->SetShouldBeVisibleInEditor(true);
	StreamingLevel->bShouldBlockOnLoad = false;
	StreamingLevel->PackageNameToLoad = LevelPackageName;
	StreamingLevel->bLocked = true;
	//world->AddUniqueStreamingLevel(StreamingLevel);
	World->AddStreamingLevel(StreamingLevel);
	//world->UpdateStreamingLevelShouldBeConsidered(StreamingLevel);
	//world->UpdateStreamingLevelPriority(StreamingLevel);
	//world->PopulateStreamingLevelsToConsider();
	//world->SetShouldForceVisibleStreamingLevels(true);
	World->UpdateLevelStreaming();
	World->RefreshStreamingLevels();
	World->FlushLevelStreaming();
}

bool USmartWorldExtensions::SmRemoveLevel(UWorld* World, ULevel * InLevel)
{
	return World->RemoveLevel(InLevel);
}

bool USmartWorldExtensions::SmSave(UWorld * World)
{
	//return FEditorFileUtils::SaveMap(world, world->GetPathName());
	return FEditorFileUtils::SaveLevel(World->PersistentLevel);
}


